/*
 * Wazuh Vulnerability scanner
 * Copyright (C) 2015, Wazuh Inc.
 * Oct 26, 2023.
 *
 * This program is free software; you can redistribute it
 * and/or modify it under the terms of the GNU General Public
 * License (version 2) as published by the FSF - Free Software
 * Foundation.
 */

#include "argsParser.hpp"
#include "databaseFeedManager.hpp"
#include "json.hpp"
#include "loggerHelper.h"
#include "routerModule.hpp"
#include "routerProvider.hpp"
#include "singleton.hpp"
#include <filesystem>
#include <iostream>

/**
 * @brief Dummy class to replace real IndexerConnector.
 *
 */
class DummyIndexerConnector
{
public:
    /**
     * @brief No operation method.
     *
     * @param message
     */
    void publish(const std::string& message) {}
};

/**
 * @brief Dummy class to replace real PolicyManager.
 *
 */
class DummyPolicyManager : public Singleton<DummyPolicyManager>
{
public:
    /**
     * @brief This method sets the topic for the subscriber.
     *
     * @param topic The topic to subscribe to.
     */
    void setUpdaterConfiguration(const std::string& topic)
    {
        m_topic = topic;
    }

    /**
     * @brief Retrieves the UpdaterConfiguration.
     *
     * @return nlohmann::json A simple JSON object with the configured topic.
     */
    nlohmann::json getUpdaterConfiguration()
    {
        auto updaterConfiguration = nlohmann::json::object();
        updaterConfiguration["topicName"] = m_topic;
        return updaterConfiguration;
    }

    /**
     * @brief Get translation LRU size.
     *
     * @return uint32_t translation LRU size.
     */
    uint32_t getTranslationLRUSize() const
    {
        return 2048;
    }

    /**
     * @brief Get osdata LRU size.
     *
     * @return uint32_t osdata LRU size.
     */
    uint32_t getOsdataLRUSize() const
    {
        return 1000;
    }

private:
    std::string m_topic;
};

/**
 * @brief Dummy class to replace real ContentRegister.
 *
 */
class DummyContentRegister
{
public:
    /**
     * @brief Constructor of the dummy class
     *
     * @param obj1 Not used.
     * @param obj2 Not used.
     */
    DummyContentRegister(const nlohmann::json& obj1, const nlohmann::json& obj2) {}

    /**
     * @brief No operation method.
     *
     * @param interval Not used.
     */
    void changeSchedulerInterval(long unsigned int interval) {}
};

int main(const int argc, const char* argv[])
{
    try
    {

        // LOGLEVEL_INFO, tag, sourceFile.file, sourceFile.line, sourceFile.func, formattedStr
        Log::assignLogFunction(
            [](const int,
               const std::string& tag,
               const std::string& file,
               const int line,
               const std::string&,
               const std::string& str,
               va_list args)
            {
                char formattedStr[MAXLEN] = {0};
                vsnprintf(formattedStr, MAXLEN, str.c_str(), args);
                std::cout << tag << "->" << file << ":" << line << " " << formattedStr << std::endl;
            });
        // Reset required directories
        if (std::filesystem::exists("./queue/vd"))
        {
            if (std::remove("./queue/vd") != 0)
            {
                std::cerr << "Error deleting directory ./queue/vd" << std::endl;
            }
        }
        std::filesystem::create_directories("./queue/vd");

        CmdLineArgs cmdLineArgs(argc, argv);

        // Read json configuration file
        auto configuration = nlohmann::json::parse(std::ifstream(cmdLineArgs.getConfigurationFilePath()));

        RouterModule::instance().start();
        auto routerProvider = std::make_shared<RouterProvider>(configuration.at("topicName"));
        routerProvider->start();

        DummyPolicyManager::instance().setUpdaterConfiguration(configuration.at("topicName"));
        std::shared_mutex mutex;
        std::atomic<bool> shouldStop {false};

        auto databaseFeedManager =
            std::make_shared<TDatabaseFeedManager<DummyIndexerConnector, DummyPolicyManager, DummyContentRegister>>(
                std::make_shared<DummyIndexerConnector>(), shouldStop, mutex, true, false);

        auto baseLine = R"(
        {
            "paths":
            [
            ],
            "offset": 0,
            "stageStatus":
            [
                {
                    "stage": "download",
                    "status": "ok"
                }
            ]
        }
        )"_json;

        baseLine["type"] = cmdLineArgs.getFormatInputFiles();
        for (const auto& path : cmdLineArgs.getInputFiles())
        {
            baseLine["paths"].push_back(path);
        }

        const auto payload = baseLine.dump();
        const auto message = std::vector<char>(payload.begin(), payload.end());

        routerProvider->send(message);
        if (cmdLineArgs.getWaitTime() > 0)
        {
            std::this_thread::sleep_for(std::chrono::seconds(cmdLineArgs.getWaitTime()));
        }
        else
        {
            std::cout << "Press enter to stop the tool..." << std::endl;
            std::cin.get();
        }
        databaseFeedManager.reset();
    }
    catch (const std::exception& e)
    {
        std::cerr << e.what() << std::endl;
        CmdLineArgs::showHelp();
        return 1;
    }
    return 0;
}
